<script setup lang="ts">
import { getTokenHeader } from '@/utils/auth'
import { computed, ref, watch, inject, reactive, toRefs } from 'vue'
import type { UploadInstance, UploadProps } from 'element-plus'
import { useFormDisabled, useFormItem } from 'element-plus'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
NProgress.configure({ showSpinner: false })

type FileType = {
  name: string
  url: string
}

const emit = defineEmits(['change'])
const oneUploadDisabled = useFormDisabled()
const { formItem } = useFormItem()
const modelValue = defineModel<string | FileType | FileType[]>({ required: true })
const name = defineModel<string>('name')
const props = withDefaults(
  defineProps<{
    action?: string
    headers?: { [x: string]: string }
    srcPath?: string
    separator?: string
    object?: boolean
    disabled?: boolean
    string?: boolean
    limit?: number
    size?: number
    types?: string[]
    withCredentials?: boolean
    width?: string
    height?: string
    hasLoading?: boolean
    onSuccess?: UploadProps['onSuccess']
    beforeUpload?: UploadProps['beforeUpload']
    onPreview?: UploadProps['onPreview']
    onExceed?: UploadProps['onExceed']
    onProgress?: UploadProps['onProgress']
  }>(),
  {
    action: import.meta.env.VITE_APP_UPLOAD_URL as string,
    headers: () => getTokenHeader(),
    srcPath: 'object.url',
    object: false,
    string: false,
    disabled: false,
    separator: ',',
    limit: 1000,
    size: 10,
    types: () => ['gif', 'jpg', 'jpeg', 'png'],
    withCredentials: true,
    width: '200',
    height: '200',
    hasLoading: true
  }
)

const dUploadRef = ref<UploadInstance>()
const valueList = ref<FileType[]>([])

const isValueObject = computed(() => {
  return Object.prototype.toString.call(valueList.value) === '[object Object]'
})
const fileInfoPath = computed(() => {
  const array = props.srcPath.split('.')
  array.pop()
  return array
})

watch(
  () => modelValue.value,
  (val) => {
    if (!val) return
    if (typeof val === 'string') {
      val && (valueList.value = [{ url: val, name: name.value }])
    } else if (Array.isArray(val)) {
      valueList.value = val
    } else if (typeof val === 'object' && val !== null && val instanceof Object) {
      valueList.value = [val]
    }
  },
  { immediate: true }
)

watch(
  valueList,
  (val) => {
    console.log(22, val)
    if (oneUploadDisabled.value) return
    const data = getModelValue(val)
    if (!data) return
    modelValue.value = data
    emit('change', data)
    formItem?.validate('change')
  },
  { deep: true }
)

// 根据类型生成组件绑定的值
function getModelValue(val: FileType[]) {
  if (props.limit === 1 && props.object) {
    return val[0]
  }
  if (props.limit === 1 && props.string) {
    console.log(1)
    name.value = val[0].name
    return val[0].url
  }
  return val
}

// 附件上传之前
const handelProgress: UploadProps['onProgress'] = (event, file, fileList) => {
  props.hasLoading && NProgress.start()
  props.onProgress && props.onProgress(event, file, fileList)
}

const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
  ElMessage.warning(`当前只能上传${props.limit}个文件，请删除后重新上传！`)
  props.onExceed && props.onExceed(files, uploadFiles)
}
const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
  if (uploadFile.url) {
    window.open(uploadFile.url)
  }
  props.onPreview && props.onPreview(uploadFile)
}

const handleBeforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
  const type = (rawFile.name.split('.').pop() || '').toLowerCase()
  if (props.types.length > 0 && !props.types.includes(type)) {
    ElMessage.error('暂不支持该格式!')
    return false
  } else if (rawFile.size > props.size * 1024 * 1024) {
    ElMessage.error(`上传文件不能超过${props.size}M`)
    return false
  }
  if (props.beforeUpload) {
    return props.beforeUpload(rawFile)
  }
  return true
}
const handleRemove: UploadProps['onRemove'] = (file, fileList) => {
  if (file.status === 'success') {
    const index = fileList.findIndex((item) => item.uid === file.uid)
    fileList.splice(index, 1)
    isValueObject.value && props.limit === 1 ? (valueList.value = []) : valueList.value.splice(index, 1)
  }
}
const handleSuccess: UploadProps['onSuccess'] = (res, file, fileList) => {
  props.hasLoading && NProgress.done()
  if (props.limit > 1 && isValueObject.value) {
    console.warn('如果上传多个附件,请绑定一个数组！')
    return
  }
  if (res.retCode === '000000') {
    let data = res
    fileInfoPath.value.forEach((key) => {
      data = data?.[key] || ''
    })
    if (!data) return
    file.url = data.url
    isValueObject.value && props.limit === 1 ? (valueList.value = data) : valueList.value.push(data)
  } else {
    fileList.pop()
    ElMessage.warning('上传失败')
  }
}
</script>

<template>
  <el-upload
    ref="dUploadRef"
    class="d-upload"
    :action="action"
    :headers="headers"
    :limit="limit"
    :disabled="oneUploadDisabled"
    :file-list="valueList"
    :class="{ 'one-upload-disabled': oneUploadDisabled }"
    :on-exceed="handleExceed"
    :on-remove="handleRemove"
    :on-success="handleSuccess"
    :on-preview="handlePreview"
    :on-progress="handelProgress"
    :before-upload="handleBeforeUpload"
    v-bind="$attrs"
    v-on="$attrs">
    <el-button type="primary" v-if="!$slots.default && !oneUploadDisabled" :disabled="oneUploadDisabled">点击上传</el-button>
    <slot />
  </el-upload>
  <div class="d-none-file" v-if="oneUploadDisabled && valueList.length === 0">无附件</div>
</template>

<style lang="scss" scoped>
.d-upload {
  width: 100%;
}
.d-none-file {
  font-size: 12px;
  line-height: 28px;
  color: var(--el-color-info);
}
.one-upload-disabled {
  :deep(.el-upload--text) {
    display: none;
  }
  :deep(.el-upload-list) {
    margin-top: 2px;
  }
}
</style>
